// --- Copyright (c) 2006-2008 Stefan Kyntchev ---
// This software is written and copyrighted by Stefan Kyntchev 
// and BeyondPod Team members. All rights are reserved.
// Author contact: support@beyondpod.mobi
// ------------------------------------------------------------------------
// This file is part of BeyondPod RSS Feed Reader and Podcast manager
// (www.codeplex.com/BeyondPod) 
// BeyondPod is free software: you can redistribute it and/or modify 
// it under the terms of the GNU General Public License as published by 
// the Free Software Foundation, either version 3 of the License, or 
// (at your option) any later version. 
//  
// BeyondPod is distributed in the hope that it will be useful, 
// but WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
// GNU General Public License for more details. 
//  
// You should have received a copy of the GNU General Public License
// along with BeyondPod. If not, see <http://www.gnu.org/licenses/>
// ------------------------------------------------------------------------
// COPYRIGHT NOTICE: This copyright notice may NOT be removed, obscured or modified 
// without written consent from the author.
// --- End copyright notice --- 


using System;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
using svs.Mobile.BeyondMedia.FeedCore;
using svs.Mobile.BeyondMedia.Properties;
using svs.Mobile.BeyondMedia.UiCore;

namespace svs.Mobile.BeyondMedia.Objects
{
	public delegate void CommandHandler();

	public enum Commands
	{
		Play_Pause = 1,
		Short_Skip_Forward,
		Short_Skip_Back,
		Long_Skip_Forward,
		Long_Skip_Back,
		GoTo_End_Of_Track,
		Next_Track,
		Prev_Track,
		Exit,
		Volume_Up,
		Volume_Down,
		Stop,
		RefreshFeeds,
		TogglePlaylist
	}

	public class Shortcut
	{
		private const Keys NO_KEY = Keys.CapsLock;
		private readonly Commands m_CommandID;
		private readonly string m_CommandName;
		private readonly CommandHandler m_handler;
		public Keys m_keyCode;

		public Shortcut(Commands i_cmdID, string i_cmdName, Keys i_key, CommandHandler i_handler)
		{
			m_keyCode = i_key;
			m_handler = i_handler;
			m_CommandID = i_cmdID;
			m_CommandName = i_cmdName;
		}

		/// <summary>
		/// Gets the command ID.
		/// </summary>
		/// <value>The command ID.</value>
		public Commands CommandID
		{
			get { return m_CommandID; }
		}

		/// <summary>
		/// Gets the name of the key.
		/// </summary>
		/// <value>The name of the key.</value>
		public string KeyName
		{
			get
			{
				if (m_keyCode != NO_KEY)
				{
					string name = m_keyCode.ToString();
					if (name.StartsWith("D") && name.Length == 2)
						return name.Substring(1);
				
					return name;
				}
				return String.Empty;
			}
		}

		/// <summary>
		/// Gets or sets the key code.
		/// </summary>
		/// <value>The key code.</value>
		public Keys KeyCode
		{
			get { return m_keyCode; }

			set { m_keyCode = value; }
		}

		/// <summary>
		/// Gets the name of the command.
		/// </summary>
		/// <value>The name of the command.</value>
		public string CommandName
		{
			get { return m_CommandName; }
		}

		/// <summary>
		/// System keys have hardcoded mapping and are not user assignable
		/// </summary>
		public bool IsSystemKey { get; set; }

		/// <summary>
		/// Invokes the specified Shortcut.
		/// </summary>
		/// <returns></returns>
		public bool Invoke()
		{
			if (KeyCode != NO_KEY && m_handler != null)
			{
				try
				{
					m_handler();
				}
				catch (Exception ex)
				{
					MessageBoxEx.Show(ex.Message, Resources.GenericExceptionTitle);
				}
				return true;
			}

			return false;
		}

		/// <summary>
		/// Clears the key assignment.
		/// </summary>
		public void ClearKeyAssignment()
		{
			KeyCode = NO_KEY;
		}
	}

	internal class ShortcutKeyManager
	{
		private static readonly ShortcutList m_Handlers = new ShortcutList();

		static ShortcutKeyManager()
		{
			//Play Pause
			m_Handlers.Add(new Shortcut(Commands.Play_Pause,
			                            "Play/Pause",
			                            Keys.Enter,
			                            CommandManager.CmdPlayPause));

			//Short Skip Forward
			m_Handlers.Add(new Shortcut(Commands.Short_Skip_Forward,
			                            "Skip " + Configuration.ShortSkipInterval + "s. Forward",
			                            Keys.Right,
			                            CommandManager.CmdShortSkipForward));

			//Short Skip Back
			m_Handlers.Add(new Shortcut(Commands.Short_Skip_Back,
			                            "Skip " + Configuration.ShortSkipInterval + "s. Back",
			                            Keys.Left,
			                            CommandManager.CmdShortSkipBack));

			//Long Skip Forward
			m_Handlers.Add(new Shortcut(Commands.Long_Skip_Forward,
			                            "Skip " + Configuration.LongSkipInterval + "s. Forward",
			                            Keys.D3,
			                            CommandManager.CmdLongSkipForward));

			//Long Skip Back
			m_Handlers.Add(new Shortcut(Commands.Long_Skip_Back,
			                            "Skip " + Configuration.LongSkipInterval + "s. Back",
			                            Keys.D1,
			                            CommandManager.CmdLongSkipBack));

			//Skip Track
			m_Handlers.Add(new Shortcut(Commands.GoTo_End_Of_Track,
			                            "End of Track",
			                            Keys.D2,
			                            CommandManager.CmdGoToTheEndOfTrack));

			//Next Track
			m_Handlers.Add(new Shortcut(Commands.Next_Track,
			                            "Play Next Track",
			                            Keys.D6,
			                            CommandManager.CmdPlayNextTrack));
			//Prev track
			m_Handlers.Add(new Shortcut(Commands.Prev_Track,
			                            "Play Prev Track",
			                            Keys.D4,
			                            CommandManager.CmdPlayPreviousTrack));

			//Exit
			var exit = new Shortcut(Commands.Exit,
			                        "Exit",
			                        Keys.F24,
			                        CommandManager.CmdExitApplication);
			exit.ClearKeyAssignment(); //We don't need anythihg assigned on exit by default
			m_Handlers.Add(exit);

			//Volume Up
			m_Handlers.Add(new Shortcut(Commands.Volume_Up,
			                            "Volume Up",
			                            Keys.Up,
			                            CommandManager.CmdVolumeUp));

			//Volume Down
			m_Handlers.Add(new Shortcut(Commands.Volume_Down,
			                            "Volume Down",
			                            Keys.Down,
			                            CommandManager.CmdVolumeDown));
			//Stop
			m_Handlers.Add(new Shortcut(Commands.Stop,
			                            "Stop",
			                            Keys.D7,
			                            CommandManager.CmdStop));

			//Stop
			m_Handlers.Add(new Shortcut(Commands.TogglePlaylist,
			                            "Toggle Playlist",
			                            Keys.D8,
			                            CommandManager.CmdTogglePlaylist));

			//=================== SYSTEM KEYS =======================================

			//Back Button
			var back = new Shortcut(Commands.RefreshFeeds,
			                        "Back Button",
			                        Keys.Escape,
			                        CommandManager.CmdGoBack);
			back.IsSystemKey = true;
			m_Handlers.Add(back);

			LoadCustomMappings();
		}

		public static ShortcutList Shortcuts
		{
			get { return m_Handlers; }
		}

		/// <summary>
		/// Handles a key.
		/// </summary>
		/// <param name="i_key">The i_key.</param>
		public static bool HandleKey(Keys i_key)
		{
			Shortcut s = GetHandlerForKey(i_key);
			if (s != null)
				return s.Invoke();

			return false;
		}

		/// <summary>
		/// Gets the handler for key.
		/// </summary>
		/// <param name="i_key">The i_key.</param>
		/// <returns></returns>
		private static Shortcut GetHandlerForKey(Keys i_key)
		{
			foreach (Shortcut handler in m_Handlers)
			{
				if (handler.KeyCode == i_key)
					return handler;
			}

			return null;
		}

		/// <summary>
		/// Loads the mappings from storage
		/// </summary>
		public static void LoadCustomMappings()
		{
			char[] kdels = {','};
			char[] pdels = {'|'};

			string[] keys = Configuration.ShortcutKeys.Split(kdels);
			if (keys.Length == 0)
				return;

			foreach (string keypair in keys)
			{
				string[] parts = keypair.Split(pdels);
				if (parts.Length != 2)
					continue;

				try
				{
					var cmd = (Commands) int.Parse(parts[0]);
					var key = (Keys) int.Parse(parts[1]);

					UpdateMapping(cmd, key);
				}
				catch
				{
					continue;
				}
			}
		}

		/// <summary>
		/// Overrides the default mappings.
		/// </summary>
		/// <param name="cmd">The CMD.</param>
		/// <param name="key">The key.</param>
		private static void UpdateMapping(Commands cmd, Keys key)
		{
			foreach (Shortcut handler in m_Handlers)
			{
				if (handler.CommandID == cmd)
				{
					handler.KeyCode = key;
					return;
				}
			}
		}

		/// <summary>
		/// Saves the key mappings.
		/// </summary>
		public static void SaveMappings()
		{
			var data = new StringBuilder();

			bool first = true;
			foreach (Shortcut handler in m_Handlers)
			{
				data.AppendFormat(CultureInfo.InvariantCulture, "{0}{1}|{2}", first ? "" : ",", (int) handler.CommandID,
				                  (int) handler.KeyCode);
				first = false;
			}

			Configuration.ShortcutKeys = data.ToString();
		}

		/// <summary>
		/// Sets the shortcut key assignment. Clears any other assignment of the same key
		/// </summary>
		/// <param name="s">The s.</param>
		/// <param name="i_key">The i_key.</param>
		internal static void SetShortcutKey(Shortcut s, Keys i_key)
		{
			Shortcut current = GetHandlerForKey(i_key);
			if (current != null)
				ClearShortcutKey(current);

			s.KeyCode = i_key;
		}

		/// <summary>
		/// Clears the shortcut key assignment.
		/// </summary>
		/// <param name="s">The s.</param>
		internal static void ClearShortcutKey(Shortcut s)
		{
			s.ClearKeyAssignment();
		}
	}
}